package org.budo.support.java.awt.robot;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.font.TextAttribute;
import java.awt.image.BufferedImage;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;

import org.budo.support.lang.util.RandomUtil;

/**
 * @author limingwei
 */
public class BudoGraphicsImpl implements BudoGraphics {
    private BudoImage _budoImage;

    private Graphics _graphics;

    private Color color;

    public BudoGraphicsImpl(BudoImage budoImage, Graphics graphics) {
        this._budoImage = budoImage;
        this._graphics = graphics;
    }

    private Graphics graphics() {
        if (null == this.color) {
            this.colorRandom();
        }

        return this._graphics;
    }

    @Override
    public BudoGraphics antialias() {
        Graphics2D graphics2d = (Graphics2D) this.graphics();

        // 消除文字锯齿
        graphics2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

        // 消除画图锯齿
        graphics2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        return this;
    }

    @Override
    public BudoGraphics rotate(Number theta) {
        Graphics2D graphics2d = (Graphics2D) this.graphics();
        graphics2d.rotate(theta.doubleValue());
        return this;
    }

    @Override
    public BudoGraphics rotate(Number theta, Number x, Number y) {
        Graphics2D graphics2d = (Graphics2D) this.graphics();
        graphics2d.rotate(theta.doubleValue(), x.doubleValue(), y.doubleValue());
        return this;
    }

    @Override
    public BudoGraphics color(Color color) {
        this._graphics.setColor(this.color = color);
        return this;
    }

    @Override
    public BudoImage image() {
        return this._budoImage;
    }

    @Override
    public BudoGraphics colorRandom() {
        int r = RandomUtil.randomInt(0, 255);
        int g = RandomUtil.randomInt(0, 255);
        int b = RandomUtil.randomInt(0, 255);

        return this.color(new Color(r, g, b));
    }

    @Override
    public BudoGraphics color(int r, int g, int b) {
        return this.color(new Color(r, g, b));
    }

    @Override
    public BudoGraphics red() {
        return this.color(Color.RED);
    }

    @Override
    public BudoGraphics green() {
        return this.color(Color.GREEN);
    }

    @Override
    public BudoGraphics yellow() {
        return this.color(Color.YELLOW);
    }

    @Override
    public BudoGraphics blue() {
        return this.color(Color.BLUE);
    }

    @Override
    public BudoGraphics white() {
        return this.color(Color.WHITE);
    }

    @Override
    public BudoGraphics lightGray() {
        return this.color(Color.LIGHT_GRAY);
    }

    @Override
    public BudoGraphics darkGray() {
        return this.color(Color.DARK_GRAY);
    }

    @Override
    public BudoGraphics orange() {
        return this.color(Color.ORANGE);
    }

    @Override
    public BudoGraphics pink() {
        return this.color(Color.PINK);
    }

    @Override
    public BudoGraphics drawLine(int x1, int y1, int x2, int y2) {
        this.graphics().drawLine(x1, y1, x2, y2);
        return this;
    }

    @Override
    public BudoGraphics drawCross(int x, int y) {
        this.graphics().drawLine(x, 0, x, _budoImage.height());
        this.graphics().drawLine(0, y, _budoImage.width(), y);

        this.graphics().drawString("Cross(" + x + "," + y + ")", x + 2, y + 12);
        this.graphics().drawString(_budoImage.rgb(x, y) + "", x + 2, y + 30);

        return this;
    }

    @Override
    public BudoGraphics drawImage(BudoImage image, int x, int y) {
        BufferedImage bufferedImage = ((BudoImageImpl) image).getBufferedImage();
        this.graphics().drawImage(bufferedImage, x, y, null);
        return this;
    }

    @Override
    public BudoGraphics drawImage(Image image, int x, int y, int width, int height) {
        this.graphics().drawImage(image, x, y, width, height, null);
        return this;
    }

    @Override
    public BudoGraphics drawRect(int x, int y, int w, int h) {
        this.graphics().drawRect(x, y, w, h);

        this.graphics().drawString("Rect(" + x + "," + y + "," + w + "," + h + ")", x + 2, y + 12);
        return this;
    }

    @Override
    public BudoGraphics drawRect(Rectangle rectangle) {
        int x = (int) rectangle.getX();
        int y = (int) rectangle.getY();
        int width = (int) rectangle.getWidth();
        int height = (int) rectangle.getHeight();

        return this.drawRect(x, y, width, height);
    }

    @Override
    public BudoGraphics fontSize(int fontSize) {
        Font font = this.graphics().getFont();
        Font fontNew = new Font(font.getName(), font.getStyle(), fontSize);
        this.graphics().setFont(fontNew);
        return this;
    }

    @Override
    public BudoGraphics fontStyle(int style) {
        Font font = this.graphics().getFont();
        Font fontNew = new Font(font.getName(), style, font.getSize());
        this.graphics().setFont(fontNew);
        return this;
    }

    @Override
    public BudoGraphics drawStrikeThroughString(String text, int x, int y) {
        AttributedString attributedString = new AttributedString(text);
        attributedString.addAttribute(TextAttribute.FONT, this.graphics().getFont());
        attributedString.addAttribute(TextAttribute.STRIKETHROUGH, TextAttribute.STRIKETHROUGH_ON, 0, text.length());
        AttributedCharacterIterator attributedCharacterIterator = attributedString.getIterator();
        this.graphics().drawString(attributedCharacterIterator, x, y);
        return this;
    }

    @Override
    public BudoGraphics drawString(String text, int x, int y) {
        this.graphics().drawString(text, x, y);
        return this;
    }

    @Override
    public BudoGraphics drawString(String text) {
        int x = (int) (this.image().width() * 0.2);
        int y = (int) (this.image().height() * 0.4);
        return this.drawString(text, x, y);
    }

    @Override
    public BudoGraphics fillRect(int x, int y, int w, int h) {
        this.graphics().fillRect(x, y, w, h);
        return this;
    }

    @Override
    public BudoGraphics drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) {
        this.graphics().drawArc(x, y, width, height, startAngle, arcAngle);
        return this;
    }

    @Override
    public BudoGraphics fillRect(Rectangle rectangle) {
        return this.fillRect((int) rectangle.getX(), (int) rectangle.getY(), //
                (int) rectangle.getWidth(), (int) rectangle.getHeight());
    }

    @Override
    public BudoGraphics fillRect() {
        return this.fillRect(0, 0, _budoImage.width(), _budoImage.height());
    }

    @Override
    public BudoGraphics drawString(String text, int x, int y, int w, int h) {
        if (null == text || text.isEmpty()) {
            return this;
        }

        double len = 0;
        int row = 0;
        String buf = "";

        char[] chars = text.toCharArray();
        for (char ch : chars) {
            if (ch < 'z') {
                len += 0.5; // 半宽字符
            } else {
                len += 1; // 1倍宽字符
            }

            buf += ch;

            if (len >= w) {
                this.drawString(buf, x, y + (row * h));

                // 换行
                buf = "";
                len = 0;
                row++;
            }
        }

        if (null != buf && !buf.isEmpty()) {
            this.drawString(buf, x, y + (row * h));
        }

        return this;
    }
}